package com.cgwx.springsecurity.filter;

import com.alibaba.fastjson.JSON;
import com.cgwx.commonutils.IpUtil;
import com.cgwx.commonutils.JwtUtils;
import com.cgwx.commonutils.ResponseUtil;
import com.cgwx.commonutils.result.SysResult;
import com.cgwx.commonutils.result.SysResultCodeEnum;
import com.cgwx.springsecurity.custom.CustomUser;
import com.cgwx.springsecurity.entity.LoginVo;
import com.cgwx.springsecurity.service.SysLoginLogService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author GaoWei
 * @Date 2023/10/21 - 11:34
 * 登录过滤器，继承UsernamePasswordAuthenticationFilter，对用户名密码进行登录校验
 */
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

    private RedisTemplate redisTemplate;
    private SysLoginLogService sysLoginLogService;

//    构造
    public TokenLoginFilter(AuthenticationManager authenticationManager,
                            RedisTemplate redisTemplate,
                            SysLoginLogService sysLoginLogService) {
        this.setAuthenticationManager(authenticationManager);
        this.setPostOnly(false);
        //指定登录接口及提交方式
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/system/login/user/login","POST"));
        this.redisTemplate = redisTemplate;
        this.sysLoginLogService = sysLoginLogService;
    }

//    登录认证
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
            throws AuthenticationException {
        try {
            LoginVo loginVo = new ObjectMapper().readValue(req.getInputStream(), LoginVo.class);
            Authentication authenticationToken = new UsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword());
            return this.getAuthenticationManager().authenticate(authenticationToken);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

//    认证成功调用
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
                                            Authentication auth) {
//        获取认证对象
        CustomUser customUser = (CustomUser) auth.getPrincipal();
//        权限数据保存到redis中，用户名称为key
        redisTemplate.opsForValue().set(customUser.getUsername(), JSON.toJSONString(customUser.getAuthorities()));
//        生成token
        String token = JwtUtils.createToken(customUser.getSysUser().getId(), customUser.getSysUser().getUsername());
//        记录登录日志
        sysLoginLogService.recordLoginLog(customUser.getUsername(), 1, IpUtil.getIpAddress(request),"登录成功");
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        ResponseUtil.out(response, SysResult.ok(map));
    }

//    认证失败调用
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                              AuthenticationException e) {
        if(e.getCause() instanceof RuntimeException) {
            ResponseUtil.out(response, SysResult.build(null, 204, e.getMessage()));
        } else {
            ResponseUtil.out(response, SysResult.build(null, SysResultCodeEnum.LOGIN_MOBLE_ERROR));
        }
    }
}
